package de.unistuttgart.iaaskpimonitoring.esper.processingmanagement.nodeImpl;

import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

import com.espertech.esper.client.EPServiceProvider;

import de.unistuttgart.iaaskpimonitoring.esper.processingmanagement.MMOperatorNode;
import de.unistuttgart.iaaskpimonitoring.esper.processingmanagement.NodeFactory;

public class DurationNodeFactory implements NodeFactory {

	public MMOperatorNode createNode(Element DOMElement,
			Element attachmentsElement, MMOperatorNode parent,
			EPServiceProvider EPService) {

		Element attachment = null;
		NodeList attachments = attachmentsElement.getElementsByTagName("attachment");
		for (int i = 0; i < attachments.getLength(); i++) {
			if (((Element) attachments.item(i))
					.getAttributeNode("attachmentID").getNodeValue().equals(
							DOMElement.getAttributeNode("attachmentID")
									.getNodeValue())) {
				attachment = (Element) attachments.item(i);
			}
		}

		MMOperatorNode toReturn = new MMOperatorNode();

		// Attributes independent of the children
		toReturn.setOutputStreamName("duration"
				+ (++MMOperatorNode.nodeLatestDistributedID));
		toReturn.setOutputMetric("duration");

		toReturn.setParent(parent);

		/*
		 * Parameters to get : activityID or processID activityStartEventName or
		 * processStartEventName activityEndEventName or processEndEventName
		 */
		// toReturn.setParameters();
		// Children nodes not for atomic operators like state, duration,
		// count...
		/*
		 * NodeList childrenElements = DOMElement.getChildNodes(); if
		 * (childrenElements.getLength() > 0) { List<MMOperatorNode> children =
		 * new ArrayList<MMOperatorNode>(4); for (int i = 0; i <
		 * childrenElements.getLength(); i++) { Element currentChildRoot =
		 * (Element) childrenElements.item(i);
		 * children.add(NodeFactoryManager.getInstance(
		 * currentChildRoot.getLocalName()).createNode( currentChildRoot,
		 * attachmentsElement, toReturn, EPService)); }
		 * 
		 * toReturn.getChildren(); toReturn.setChildren(children); }
		 */
		String statementString = new String();
		String statementForFilter1String = new String();
		String statementForFilter2String = new String();

		if (attachment.getAttribute("attachmentType").equals("process")) {
			statementForFilter1String
					.concat("INSERT INTO "
							+ toReturn.getOutputStreamName()
							+ "start"
							+ " SELECT "
							+ " timestamp AS timestamp,"
							+ " processInstanceID AS processInstanceID"
							+ " *,"
							+ " FROM de.unistuttgart.iaasskpimonitoring.esper.eventmanagement.ProcessEvent(name='processStartEvent' and processID="
							+ toReturn.getParameters().get("processID") + ")");

			statementForFilter2String
					.concat("INSERT INTO "
							+ toReturn.getOutputStreamName()
							+ "end"
							+ " SELECT "
							+ " timestamp AS timestamp,"
							+ " processInstanceID AS processInstanceID"
							+ " *,"
							+ " FROM de.unistuttgart.iaasskpimonitoring.esper.eventmanagement.ProcessEvent(name='processCompletionEvent' and processID="
							+ toReturn.getParameters().get("processID") + ")");
		} else {
			statementForFilter1String
					.concat("INSERT INTO "
							+ toReturn.getOutputStreamName()
							+ "start"
							+ " SELECT "
							+ " timestamp AS timestamp,"
							+ " processInstanceID AS processInstanceID"
							+ " *,"
							+ " FROM de.unistuttgart.iaasskpimonitoring.esper.eventmanagement.ActivityEvent(name='activityStartEvent' and activityID="
							+ toReturn.getParameters().get("activityID") + ")");

			statementForFilter2String
					.concat("INSERT INTO "
							+ toReturn.getOutputStreamName()
							+ "end"
							+ " SELECT "
							+ " timestamp AS timestamp,"
							+ " processInstanceID AS processInstanceID"
							+ " *,"
							+ " FROM de.unistuttgart.iaasskpimonitoring.esper.eventmanagement.ActivityEvent(name='activityCompletionEvent' and activityID="
							+ toReturn.getParameters().get("activityID") + ")");
		}

		statementString
				.concat("INSERT INTO "
						+ toReturn.getOutputStreamName()
						+ " SELECT "
						+ " abs(b.timestamp - a.timestamp) AS , " + toReturn.getOutputMetric()
						+ " a.processInstanceID AS processInstanceID, "
						+ " de.unistuttgart.iaaskpimonitoring.esper.eventmanagement.EventUtils.addInCorrelationSet(a.processInstanceID) AS correlationSet, "
						+ " a.activityID AS activityID, "
						+ " processInstanceID AS processInstanceID, ");

		if (attachment.getAttribute("attachmentType").equals("activity")) {
			statementString
					.concat(" FROM PATTERN [(every a="
							+ toReturn.getOutputStreamName()
							+ "start(activityID = "
							+ toReturn.getParameters().get("activityID")
							+ ") -> b ="
							+ toReturn.getOutputStreamName()
							+ "end(activityID = a.activityID and processInstanceID = a.processInstanceID) )"
							+ " OR (every b="
							+ toReturn.getOutputStreamName()
							+ "end(activityID = "
							+ toReturn.getParameters().get("activityID")
							+ ") -> a ="
							+ toReturn.getOutputStreamName()
							+ "start(activityID = b.activityID and processInstanceID = b.processInstanceID) )]");
		} else {
			statementString
					.concat(" FROM PATTERN [(every a="
							+ toReturn.getOutputStreamName()
							+ "start(processID = "
							+ toReturn.getParameters().get("processID")
							+ ") -> b ="
							+ toReturn.getOutputStreamName()
							+ "end(processID = a.processID and processInstanceID = a.processInstanceID) )"
							+ " OR (every b="
							+ toReturn.getOutputStreamName()
							+ "end(processID = "
							+ toReturn.getParameters().get("processID")
							+ ") -> a ="
							+ toReturn.getOutputStreamName()
							+ "start(processID = b.processID and processInstanceID = b.processInstanceID) )]");
		}

		// Creation of the statements that are directly registered in the engine
		// !
		toReturn.setStatement(EPService.getEPAdministrator().createEPL(
				statementForFilter1String));
		toReturn.setStatement(EPService.getEPAdministrator().createEPL(
				statementForFilter2String));
		toReturn.setStatement(EPService.getEPAdministrator().createEPL(
				statementString));

		return toReturn;
	}
}
